﻿#define _CRT_SECURE_NO_WARNINGS

//4.19

//struct Stack
//class Stack
//{
//public:
//	// 成员函数
//	void Init(int defaultCapacity = 4)	//在类里面定义
//	{
//		a = (int*)malloc(sizeof(int) * capacity);	
//		if (nullptr == a)
//		{
//			perror("malloc申请空间失败");
//			return;
//		}
//
//		capacity = defaultCapacity;
//		top = 0;
//	}
//
//	void Push(int x)
//	{
//		//...
//		a[top++] = x;
//	}
//
//	void Destroy()
//	{
//		free(a);
//		a = nullptr;
//		top = capacity;
//	}
//
//	// ....
//private:
//	// 成员变量
//	int* a;
//	int top;
//	int capacity;
//};  
//
//class Date
//{
//public:
//	void Init(int year)
//	{
//		// 这里的year到底是成员变量，还是函数形参？
//		_year = year;
//	}
//private:
//	int _year; // year_
//	int _month;
//	int _day;
//};
//
// 
//封装是一个管理规范，防止不规范、不文明的行为
//
// 
//声明和定义的本质区别是，是否开辟空间
//
//
//#include"Func.h"
//
// C++兼容c语言。 struct以前的用法都可以继续用
// 同时struct升级成了类
//int main()
//{
//	struct Stack st1;
//	st1.Init(20);
//
//	Stack st2;
//	st2.Init();
//	st2.Push(1);
//	st2.Push(2);
//	st2.Push(3);
//	st2.Push(4);
//	st2.Destroy();
//
//	return 0;
//}
//
//int main()
//{
//	// 类实例化对象/对象定义
//	Stack st1;
//	Stack st2;
//	//st1.top = 1;
//
//	// 不能,类访问top是声明，声明不能存数据
//	//Stack::top = 1;
//
//	return 0;
//}
//
//int main()
//{
//	// 类实例化对象/对象定义
//	Stack st1;
//	Stack st2;
//	Stack st3;
//	Stack st4;
//
//	st1.top = 0;
//	st1.Push(1);
//
//	st2.top = 1;
//	st2.Push(1);
//
//	//对象的大小只算成员变量，不算成员函数
//	// 对象中只存储的成员变量，没有存储成员函数
//	cout << sizeof(st1) << endl;
//
//	return 0;
//}

//4.22

//#include<iostream>
//using namespace std;

//class A
//{
//public:
//	void PrintA()
//	{
//		cout << _a << endl;
//	}
//private:
//	char _a;
//};
//
//int main()
//{
//	A aa1;
//	A aa2;
//	cout << sizeof(A) << endl;
//	cout << sizeof(aa1) << endl;
//	aa1._a = '1';
//	aa1.PrintA();
//
//	return 0;
//}
//
//
//// 类中仅有成员函数
//class A2 {
//public:
//    void f2() {}
//};
//
//// 类中什么都没有---空类
//class A3
//{};
//
////int main()
////{
////    //cout << sizeof(A1) << endl;
////
////    // 没有成员变量的类对象，需要1byte，是为了占位，表示对象存在
////    // 但不存储有效数据
////    cout << sizeof(A2) << endl;	//1
////    cout << sizeof(A3) << endl;	//1
////    A2 aa1;
////    A2 aa2;
////    cout << &aa1 << endl;
////    cout << &aa2 << endl;
////
////    return 0;
////}
//
//class Date
//{
//public:
//	void Init(int year, int month, int day)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	// d1.Print();
//	// d2.Print();
//	void Print()
//	{
//		// this不能在形参和实参显示传递，但是可以在函数内部显示使用
//		//this = nullptr;
//		cout << this << endl;
//		cout << this->_year << "-" << _month << "-" << _day << endl;
//	}
//
//	// 编译器会成员函数的处理
//	/*void Print(Date* const this)
//	{
//		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
//	}*/
//
////private:
//	int _year;     // 年   声明
//	int _month;    // 月
//	int _day;      // 日
//};
//
//int main()
//{
//	Date d1, d2;
//	d1.Init(2022, 1, 11);
//	d2.Init(2022, 1, 12);
//	d1.Print();
//	d2.Print();
//
//	//Date::_year;
//	//d1._year;
//
//	/*d1.Print(&d1);
//	d2.Print(&d2);*/
//
//    return 0;
//}
//
//
//this指针是形参，故与普通参数一样，存在函数调用的栈帧里
//vs下对this指针传递进行了优化，对象的地址放在ecx，ecx存储this指针的值
//
//
// 1.下面程序编译运行结果是？ A、编译报错 B、运行崩溃 C、正常运行
//class A
//{
//public:
//	void Print()
//	{
//		cout << "Print()" << endl;
//	}
//private:
//	int _a;
//};
//int main()
//{
//	A* p = nullptr;
//	p->Print();
//	return 0;
//}
//
//  C
// 语法没有问题故与编译无关；
// p调用print不会发生解引用
// 因为print的地址不在对象中，p会作为实参传给this指针
// 虽然this指针为空，但函数内没有对其解引用，故正常运行
// 
//// 2.下面程序编译运行结果是？ A、编译报错 B、运行崩溃 C、正常运行
//class A
//{
//public:
//	void PrintA()
//	{
//		cout << _a << endl;
//	}
//
//private:
//	int _a;
//};
//int main()
//{
//	A* p = nullptr;
//	p->PrintA();
//	return 0;
//}
// 
// B
// p调用print不会发生解引用
// 因为print的地址不在对象中，p会作为实参传给this指针
// this指针为空，函数访问_a即是在对其解引用（this->_a），对空指针解引用故运行崩溃
//
//
//
//
//class A
//{
//public:
//	void Print()
//	{
//		cout << "Print()" << endl;
//	}
//private:
//	int _a;
//};
//
//int main()
//{
//	A* p = nullptr;
//	p->Print();
//
//	//不可用
//	/*A::Print(nullptr);
//	A::Print(p);*/
//
//
//	return 0;
//}

//typedef int DataType;
//class Stack
//{
//public:
//	Stack(DataType* a, int n)
//	{
//		cout << "Stack(DataType* a, int n)" << endl;
//		_array = (DataType*)malloc(sizeof(DataType) * n);
//		if (NULL == _array)
//		{
//			perror("malloc申请空间失败!!!");
//			return;
//		}
//		memcpy(_array, a, sizeof(DataType) * n);
//
//		_capacity = n;
//		_size = n;
//	}
//
//	Stack(int capacity = 4)
//	{
//		cout << "Stack(int capacity = 4)" << endl;
//		_array = (DataType*)malloc(sizeof(DataType) * capacity);
//		if (NULL == _array)
//		{
//			perror("malloc申请空间失败!!!");
//			return;
//		}
//
//		_capacity = capacity;
//		_size = 0;
//	}
//
//	/*void Init()
//	{
//		_array = (DataType*)malloc(sizeof(DataType) * 4);
//		if (NULL == _array)
//		{
//			perror("malloc申请空间失败!!!");
//			return;
//		}
//
//		_capacity = 4;
//		_size = 0;
//	}*/
//
//	void Push(DataType data)
//	{
//		CheckCapacity();
//		_array[_size] = data;
//		_size++;
//	}
//
//	void Pop()
//	{
//		if (Empty())
//			return;
//		_size--;
//	}
//
//	DataType Top() { return _array[_size - 1]; }
//	int Empty() { return 0 == _size; }
//	int Size() { return _size; }
//
//	//void Destroy()
//	//{
//	//	if (_array)
//	//	{
//	//		free(_array);
//	//		_array = NULL;
//	//		_capacity = 0;
//	//		_size = 0;
//	//	}
//	//}
//
//	~Stack()
//	{
//		cout << "~Stack()" << endl;
//		if (_array)
//		{
//			free(_array);
//			_array = NULL;
//			_capacity = 0;
//			_size = 0;
//		}
//	}
//
//private:
//	void CheckCapacity()
//	{
//		if (_size == _capacity)
//		{
//			int newcapacity = _capacity * 2;
//			DataType* temp = (DataType*)realloc(_array, newcapacity * sizeof(DataType));
//			if (temp == NULL)
//			{
//				perror("realloc申请空间失败!!!");
//				return;
//			}
//			_array = temp;
//			_capacity = newcapacity;
//		}
//	}
//private:
//	DataType* _array;
//	int _capacity;
//	int _size;
//};
//
//int main()
//{
//	Stack s;
//	//s.Init();
//
//	s.Push(1);
//	s.Push(2);
//	s.Push(3);
//	s.Push(4);
//
//	printf("%d\n", s.Top());
//	printf("%d\n", s.Size());
//
//	s.Pop();
//	s.Pop();
//	printf("%d\n", s.Top());
//	printf("%d\n", s.Size());
//
//	//s.Destroy();
//	return 0;
//}
//
// 
//
//class Date
//{
//public:
//	// 构成函数重载
//	// 但是无参调用存在歧义？
//	/*Date()
//	{
//		_year = 1;
//		_month = 1;
//		_day = 1;
//	}*/
//
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//private:
//	// 内置类型
//	// C++11支持，这里不是初始化，因为这里只是声明,没有开辟空间
//	// 这里给的是默认的缺省值，给编译器生成默认构造函数用
//	int _year = 1;
//	int _month = 1;
//	int _day = 1;
//
//	// 自定义类型
//	//Stack _st;
//};
////
//// 1、一般情况下，有内置类型成员，就需要自己写构造函数，不能用编译器自己生成的。
//// 2、全部都是自定义类型成员，可以考虑让编译器自己生成
//int main()
//{
//	// 构造函数的调用跟普通函数也不一样
//	Date d1;	//可以这么写
//	//Date d1(); // 不可以这样写，会跟函数声明有点冲突，编译器不好识别
//	Date d2(2023, 11, 11);
//	d1.Print();
//	d2.Print();
//
//	Date d3(2000);
//	d3.Print();
//
//	//Date d1;
//	//d1.Date();
//	//Date d2;
//	//d2.Date(2023, 1, 1);
//
//	return 0;
//}
// 
// 
// 
// 
// 
//不懂的细节切记查看笔记、讲义和回放

//4.25

//class Stack
//{
//public:
//	Stack()
//	{
//		cout << "Stack()" << endl;
//		_a = (int*)malloc(sizeof(int) * 4);
//		if (nullptr == _a)
//		{
//			perror("malloc fail");
//			return;
//		}
//
//		_capacity = 4;
//		_top = 0;
//	}
//// 赋缺省值
//// Stack(int capacity = 4)
////	{
////		cout << "Stack()" << endl;
////
////		_a = (int*)malloc(sizeof(int) * capacity);
////		if (nullptr == _a)
////		{
////			perror("malloc申请空间失败");
////			return;
////		}
////
////		_capacity = capacity;
////		_top = 0;
////	}
//private:
//	int* _a;
//	int _top;
//	int _capacity;
//};
//int main()
//{
//	Stack st;	
//  //Stack st();	//编译器无法区分st()是变量还是函数名
//  //自动调用构造函数
//	return 0;
//}
//内置类型成员不会用构造函数处理
// （尽管部分编译器会处理，但仍需将不处理当作常态）
// （c++11打了补丁，声明可以给缺省值，给缺省值，编译器会用缺省值初始化，但c++标准没有规定缺省值的初始化，故切不可依赖编译器来初始化）
//自定义类型成员会被调用它的默认构造
//[小结]
//一般情况下，构造函数需要自己写
//内置类型的成员都有缺省值，且初始化符合我们的实际要求，或者，全为自定义类型的构造，且这些类型都定义默认构造
//
//struct TreeNode
//{
//	TreeNode* _left;
//	TreeNode* _right;
//	int _val;
//
//	TreeNode(int val = 0)	//定义缺省值
//	{
//		_left = nullptr;
//		_right = nullptr;
//		_val = val;
//	}
//};
//class Tree
//{
//private:
//	TreeNode* _root = nullptr;	//构造函数会默认构造，按需给予缺省值即可
//};
//
//class MyQueue
//{
//private:
//	Stack _pushst;
//	Stack _popst;
//};
//int main()
//{
//
//	Tree t1;
//
//	TreeNode n0;	//默认缺省值为0
//	TreeNode n1(1);	//传缺省值
//	TreeNode n2(2);
//
//	MyQueue q;
//
//	return 0;
//}
// 
//class MyQueue
//{
//private:
//	Stack _pushst;
//	Stack _popst;
//};
//int main()
//{
//
//	MyQueue q;	//默认初始化
//
//	return 0;
//}
//
//class Stack
//{
//public:
//	Stack(int capacity = 4)
//	{
//		cout << "Stack()" << endl;
//
//		_a = (int*)malloc(sizeof(int) * capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败");
//			return;
//		}
//
//		_capacity = capacity;
//		_top = 0;
//	}
//	~Stack()
//	{
//		cout << "~Stack()" << endl;
//		free(_a);
//		_a = nullptr;
//		_capacity = _top = 0;
//	}
//private:
//	int* _a = nullptr;
//	int _top = 0;
//	int _capacity;
//};
//int main()
//{
//	Stack st;	
//
//	return 0;
//}
//出作用域后析构函数被自动调用
//同样的，内置类型不作处理，自定义类型会调用它的析构函数
// 
// 
// 不开辟动态空间无需写析构，因为调用结束后空间立刻销毁，例如日期类
//class Date	
//{
//public:
//	Date(int year = 1900, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//class MyQueue
//{
//private:
//	Stack _pushst;
//	Stack _popst;
//};


//class Date
//{
//public:
//	Date(int year = 1900, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	// d2(d1)
//	//Date(Date& d)	//拷贝构造有且只有一个参数，且必须是类的类型对象的引用
//	//Date(const Date& d)	//最好加上一个const引用，以防拷贝源和拷贝目标混淆
//	//{
//	//	cout << "Date(Date& d)" << endl;
//	//	this->_year = d._year;
//	//	_month = d._month;
//	//	_day = d._day;
//	//	/*d._year = _year;
//	//	d._month = _month;
//	//	d._day = _day;*/
//	//}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//void func(Date d)
//{
//
//}
//
//void func(int i)
//{
//
//}
////c++规定：内置类型直接拷贝，自定义类型必须调用拷贝构造完成拷贝
////非引用传参给拷贝函数，会无穷递归地生成拷贝构造
//int main()
//{
//	//Stack st1;
//	//Date d1;
//	//MyQueue q;
//
//	// 可以不写，默认生成的拷贝构造就可以用
//	Date d1(2023, 4, 25);
//	Date d2(d1);	//函数中，d是d1的别名传给函数，d2传给this指针
//
//	func(d1);
//	func(10);
//
//	//栈的拷贝是深拷贝
////	// 深拷贝必须由我们自己实现
////	Stack st1;
////	Stack st2(st1);
//
//	return 0;
//}
// 
//若未显示定义，编译器会生成默认的拷贝构造函数
//1.内置类型成员完成值拷贝（浅拷贝）
//2.自定义类型成员会调用它的拷贝构造
//也就是说，就算没有写拷贝构造函数，内置类型和自定义类型也都会被编译器处理，但是以浅拷贝的方式
//浅拷贝（不单独开辟空间）的问题：1.若发生析构两次则会报错，2.其中拷贝的一个被修改会影响另一个
//
//
//深拷贝实现
//class Stack
//{
//public:
//	Stack(int capacity = 4)
//	{
//		cout << "Stack()" << endl;
//
//		_a = (int*)malloc(sizeof(int) * capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败");
//			return;
//		}
//
//		_capacity = capacity;
//		_top = 0;
//	}
//
//	// st2(st1)
//	Stack(const Stack& st)
//	{
//		_a = (int*)malloc(sizeof(int) * st._capacity);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败");
//			return;
//		}
//
//		memcpy(_a, st._a, sizeof(int) * st._top);
//		_top = st._top;
//		_capacity = st._capacity;
//	}
//
//	~Stack()
//	{
//		cout << "~Stack()" << endl;
//		free(_a);
//		_a = nullptr;
//		_capacity = _top = 0;
//	}
//
//private:
//	int* _a = nullptr;
//	int _top = 0;
//	int _capacity;
//};
// 
// 
// 
// 
//
//class Date
//{
//public:
//	Date(int year = 1900, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	int _year;
//	int _month;
//	int _day;
//};
//bool operator<(const Date& x1, const Date& x2)
//{
//	if (x1._year < x2._year)
//	{
//		return true;
//	}
//	else if (x1._year == x2._year && x1._month < x2._month)
//	{
//		return true;
//	}
//	else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day)
//	{
//		return true;
//	}
//
//	return false;
//}
//
//bool operator>(const Date& x1, const Date& x2)
//{
//	if (x1._year > x2._year)
//	{
//		return true;
//	}
//	else if (x1._year == x2._year && x1._month > x2._month)
//	{
//		return true;
//	}
//	else if (x1._year == x2._year && x1._month == x2._month && x1._day > x2._day)
//	{
//		return true;
//	}
//
//	return false;
//}
//
//int main()
//{
//	Date d1(2025, 4, 25);
//	Date d2(2023, 5, 25);
//
//	/*cout << Func1(d1, d2) << endl;
//	cout << Func2(d1, d2) << endl;*/
//
//	// 内置类型可以直接比较，自定义类型不可以直接比较
//
//	//operator 运算符重载
//	cout << (d1 < d2) << endl;
//	//等价于
//	cout << (operator<(d1, d2)) << endl;
//
//	
//	cout << (d1 > d2) << endl;
//	//等价于
//	cout << (operator>(d1, d2)) << endl;
//
//	return 0;
//}
//


//4.26

//运算符重载
//
//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//	void Print()
//	{
//		cout << _year << "-" << _month << "-" << _day;
//	}
//	bool operator<(const Date& x)
//		//不能创造新的操作符，例如operator@
//		//不能对内置类型重载，例如 bool operator<(int& x1, int& x2)，且必须有一个类的类型参数
//		//作为类成员函数重载时，形参比操作数少一个，这是因为成员函数的第一个参数为隐藏的this
//		//操作符涉及几个操作数，重载函数就有几个参数
//		//“.*（常考）”、“::”、“sizeof”、“? ;”、“.（成员访问）”，这五个运算符不能重载
//	{
//		if (_year < x._year)
//		{
//			return true;
//		}
//		else if (_year == x._year && _month < x._month)
//		{
//			return true;
//		}
//		else if (_year == x._year && _month == x._month && _day < x._day)
//		{
//			return true;
//		}
//		return false;
//	}
//	
//	//赋值运算符重载
//	//void operator=(const Date& d)	
//	//{
//	//	//日期类 浅拷贝
//	//	_year = d._year;
//	//	_month = d._month;
//	//	_day = d._day;
//	//}
//	//i=j=k连续赋值 and d4 = d1
//	Date& operator=(const Date& d)
//		//传引用返回不调用拷贝函数，大大增加效率
//	{
//		
//		if (this != &d)	//断言防止自己赋自己，例如：d1 = d1。地址相同则不赋值
//		//if (*this != d)	//比较值，还要调用赋值函数，代价太大，不如比地址
//		{
//			_year = d._year;
//			_month = d._month;
//			_day = d._day;
//		}
//		return *this;	//this是形参，但生命周期不仅仅在类的成员函数中
//	}
//	//[ps]
//	//没有显示定义或声明时，编译器会生成一个默认赋值运算符重载，以值的方式逐字节拷贝
//	//默认生成的赋值重载跟拷贝构造的行为一样：1.内置类型成员进行值拷贝（浅拷贝），2.自定义类型成员会去调用它的赋值重载
//	//则Date（浅拷贝）和MyQueue（深拷贝）+不需要我们自己实现赋值重载，Stack需要我们自己编写深拷贝来实现
//
//
//
//	Date(const Date& d)	//验证是否调用传引用返回的赋值函数是否调用拷贝构造
//	{
//		cout << "Date(const Date& d)" << endl;
//		_year = d._year;
//		_month = d._month;
//		_day = d._day;
//	}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
//int main()
//{
//	Date d1(2023, 4, 26);
//	Date d2(2023, 6, 21);
//
//	//d1 - d2 //有意义
//	//d1 + d2 //没意义
//	//是否要重载运算符，取决于这个运算符对这个类是否有意义
//
//	d1 < d2;	//转换成operator<(d1,d2)
//	d1.operator<(d2);	//效果同上
//
//	d1 = d2;	//已经存在的两个对象之间复制拷贝 - 本质是运算符重载函数
//	Date d3(d1);	//用一个已经存在的对象初始化另一个对象 - 本质是构造函数
//
//	//连续赋值
//	int i, j, k;
//	i = j = k = 0;
//	//
//	Date d5,d4;
//	d5 = d4 = d1;
//
//	return 0;
//}
//


#include"Date.h"

//void TestDate1()
//{
//	Date d1(2023,4,26);
//	d1 += 100;
//	d1.Print();
//	Date d2(2023, 4, 26);
//	//Date d3(d2 + 100);
//	Date d3 = d2 + 100;	//拷贝构造
//	d2.Print();
//	d3.Print();
//
//	//[补]
//	Date d4 = d2;	// 用一个已经存在的对象初始化另一个对象；此处是拷贝构造，等价于 Date d4(d2);
//	//拷贝+初始化
//	d4 = d1;	//已经存在的两个对象之间复制拷贝；此处是赋值，调用运算符重载函数
//	//赋值是单纯的拷贝
//}
//void TestDate2()
//{
//	Date d1(2023, 4, 26);
//	//前置++：返回++以后的对象
//	//后置++：返回++之前的对象
//	//故不能用同一个函数进行重载
//	++d1;	// => d1.operator++()
//	d1++;	// => d1.operator++(0) - 编译器默认加一个参数0以区分前置++和后置++
//	//后置++会多创建两个对象，故效率上，使用前置++比使用后置++更好
//}
//int main()
//{
//	TestDate1();
//	return 0;
//}

//5.5

//void TestDate3()
//{
//	Date d1(2023, 5, 5);
//	d1 -= 50;
//	d1.Print();
//
//	Date d2(2023, 5, 5);
//	d2 -= 100;
//	d2.Print();
//
//	Date d3(2023, 5, 5);
//	d3 -= 1000;
//	d3.Print();
//
//	Date d4(2023, 5, 5);
//	d4 -= 10000;
//	d4.Print();
//}
//void TestDate4()
//{
//	Date d1(2023, 5, 5);
//	d1 += 100;
//	d1.Print();
//
//	Date d2(2023, 5, 5);
//	d2 += -100;
//	d2.Print();
//
//	Date d3(2023, 5, 5);
//	d3 -= -100;
//	d3.Print();
//}
//void TestDate5()
//{
//	Date d1(2023, 5, 5);
//	Date ret1=d1--;		//调用d1.operator--(&d1, 0);
//	ret1.Print();
//	d1.Print();
//
//
//	Date d2(2023, 5, 5);
//	Date ret2 = --d2;	//默认调用 d1.operator--(&d1);
//	ret2.Print();
//	d2.Print();
//
//	//int n = 10;
//	//while (n--)	//循环10次
//	//{
//
//	//}
//	//while (--n)	//循环9次
//	//{
//
//	//}
//}
//void TestDate6()
//{
//	Date d1(2023, 5, 5);
//	Date d2(2000, 1, 1);
//	cout << d1 - d2 << endl;
//	cout << d2 - d1 << endl;
//}
//void TestDate7()
//{
//	Date d1(2023, 5, 5);
//	d1 += 100;
//
//	//流插入
//	//cout << d1;	// 不能直接转换成 d1.opreator<<(cout);
//	//d1 << cout;		// 能直接转换成 d1.opreator<<(cout); ，第一个参数是左操作数，第二个参数是右操作数
//	//d1.operator<<(cout);	//但该写法不符合运算符重载，因为流插入的本质是参数流向控制台，形如cout << d1。真要完全实现，必须在库里面修改
//	cout << d1;
//	operator<<(cout, d1);
//
//	Date d2(2023, 5, 5);
//	Date d3(2000, 1, 1);
//	cout << d2 << d3 << d1;	//连续的流插入
//	//d1=d2=d3;运算符是从右往左执行的
//	//但连续流插入无法从右往左实现，应从左往右实现
//	//先返回 cout << d2的cout（out）的值
//	//然后返回 cout << d2 << d3 的cout（out）的值
//	//最后返回 cout << d2 << d3 << d1 的cout（out）的值
//
//	Date d4(2023, 13, 1);
//	cout << d4;
//}
//void TestDate8()
//{
//	Date d1(2023, 5, 5);
//	Date d2(2000, 1, 1);
//	cin >> d1 >> d2;
//	cout << d2 << d1;
//
//}
//void TestDate9()
//{
//	Date d1(2023, 5, 5);
//	d1.Print();		//转化成d1.Print(&d1);
//	//传给void Print(): Date*this,权限平移
//
//	const Date d2(2023, 5, 5);
//	d2.Print();		//无法调用Print()
//					//转化成d2.Print(&d2);
//	//传给void Print(): const Date*this，权限放大
//	//将this指针改成 const Date* this 即可
//	//而 d1.Print(&d1) 传给此时的Print()相当于是权限缩小
//	//void Print() const - 普通对象和const对象都可以调用
//	//成员函数后加const，普通对象和const对象都可以调用
//	//但不是所有成员函数后都能加const，例如修改成员变量的函数就不能加
//
//	d1 + 100;
//	d2 + 100;	//const变量不能调用operator+(int day)，
//				//必须在operator+(int day)后加上const
//				//operator+(int day)不改变成员变量，故可加const
//
//	d1 < d2;
//	d2 < d1;
//	//d1和d2可比较大小
//	//但d2和d1不可比较大小
//	//故在operator<(const Date& x)后加const，原理同上
//
//	//[小结]
//	//只要成员函数内部不修改成员变量，其后都应该加上const
//	//这样一来，普通对象和const对象都可以调用相应函数，不涉及权限问题
//}
//int main()
//{
//	//TestDate3();
//	//TestDate4();
//	//TestDate5();
//	//TestDate6();
//	//TestDate7();
//	//TestDate8();
//	TestDate9();
//
//	return 0;
//}

//5.8

//int main()
//{
//	Date d1;
//	const Date d2;
//
//	cout << &d1 << endl;
//	cout << &d2 << endl;
//
//	return 0;
//}
//
//

//再谈构造函数
//一个类初始化有两种方式，一个是构造函数体赋值，一个是初始化列表
//构造函数体赋值 - 略（见前）
//初始化列表 - 以冒号开始，然后是以逗号进行分隔的数据成员列表，每个成员变量后紧跟一个放在括号中的初始值或表达式
//初始化列表是构造函数的一部分，不能代替构造函数体赋值
//例：
//class Date
//{
//public:
//	Date(int year, int month, int day)
//		:_year(year)
//		,_month(month)
//		,_day(day)
//	{}
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//有些情况下，只有初始化列表才能解决
//[ps]
//每个成员变量至多只能在初始化列表中初始化一次；
//引用成员变量、const成员变量、自定义类型成员变量（且其没有构造函数）必须在初始化列表中初始化
//例：
// class A
//{
//public:
//	//A(int a)		//不是默认构造函数
//	//	:_a(a)
//	//{
//	//	cout << "A(int a = 0)" << endl;
//	//}
//	A(int a = 0)	//_aobj的默认构造函数
//		:_a(a)
//	{
//		cout << "A(int a = 0)" <<endl;
//	}
//private:
//	int _a;	//默认的内置类型成员。它会自动调用它的默认构造函数
//};
//
//class B
//{
//public:
//	//初始化列表 - 对象的成员定义的位置
//	B(int a, int ref)
//		:_ref(ref)
//		,_n(1)
//		,_x(2)	//当初始化列表中已赋值，不会再用缺省值对内置类型成员进行初始化
//		//,_aobj(10)	//_aobj有默认构造函数时也可如此调用
//		, _aobj(a)	//传参控制初始化.若无默认构造，则编译器要求自己写相应的构造函数调用，否则会报错 
//	{
//		//_n = 0;
//		//_ref = ref;
//	}
//
//private:
//	//以下都是变量的声明
//
//	A _aobj;	  //此处_aobj没有默认构造函数
//				  //不传参/无参、全缺省、自己不写的才是默认构造函数
//	//此时要在初始化列表中赋值，促使它去调用构造函数才可编译通过
//	//无论有没有默认构造函数，成员变量都要进初始化列表
//	//可以利用这一点手动传参，以控制参数
//
//
//	//引用成员变量和const成员变量的特征：必须在定义的时候初始化
//	int& _ref;	  // 引用成员变量
//	const int _n; // const成员变量
//	int _x = 1;  // 默认的内置类型成员。这里1是缺省值，缺省值是给初始化列表的。给了缺省值就会用缺省值去初始化
//};
//
//int main()
//{
//	//当对象定义了，其整体就定义了
//	//对象定义就要调用构造函数完成初始化
//	//而对象的成员在初始化列表中定义（类中）
//	//B bb1(10, 1); 
//	//B bb2(11, 2);
//	int n = 10;
//	B bb1（10, n);	//传引用，防止间接造成野指针。ref是局部变量，出作用域销毁，此时引用原本指向的空间已不存在。故引用也不是绝对安全的
//
//	return 0;
//}

//class Stack
//{
//public:
//	Stack(int int capacity = 10)
//		:_a((int*)malloc(capacity * sizeof(int)))	//初始化列表可以用malloc动态空间，但无法检查开辟情况
//		, _top(0)
//		, _capacity(capacity)
//	{
//		if (nullptr == _a)	//故需手动检查malloc
//		{
//			perror("malloc fail");
//			exit(-1);
//		}
//
//		//要求数组初始化		
//		memset(_a, 0, sizeof(int) * capacity);	//手动初始化。或直接用calloc
//
//		//尽管总有一些工作是初始化列表做不完的
//		//但无论是否使用初始化列表，自定义类型成员都会优先使用初始化列表进行初始化
//		//故建议直接使用初始化列表
//	}
//
//private:
//	int* _a;
//	int _top;
//	int _capacity;
//};
//
//
////开辟二维动态数组的情景，无法使用初始化列表进行初始化，必须通过函数体赋值的方式
//class AA
//{
//public:
//	AA(int row=10, int col=5)
//		:_row(row)
//		,_col(col)
//	{
//		//开辟二维动态数组
//		_aa = (int**)malloc(sizeof(int*) * row);	//开辟一位的指针数组
//		for (int i = 0; i < row; i++)
//		{
//			_aa[i] = (int*)malloc(sizeof(int) * col);
//		}
//	}
//private:
//	int* _a;
//	int _row;
//	int _col;
//};
//故按需初始化即可

//class A
//{
//public:
//	A(int a)
//		:_a1(a)
//		, _a2(_a1)
//	{}
//	void Print() {
//		cout << _a1 << " " << _a2 << endl;
//	}
//private:
//	int _a2;
//	int _a1;
//};
//int main() {
//	A aa(1);
//	aa.Print();
//}
//A.输出1  1
//B.程序崩溃
//C.编译不通过
//D.输出1  随机值
//成员变量是按声明的顺序去初始化的，_a2先被初始化，_a1后被初始化，故本题选D
//建议：声明的顺序和定义的顺序保持一致

//explicit关键字
// 
//1.隐式类型转换
//class A
//{
//public:
//	A(int a)
//		:_a(a)
//	{
//		cout << "A(int a)" << endl; //代码运行后，构造函数会被调用
//	}
//	A(const A& aa)
//		:_a(aa._a)
//	{
//		cout << "A(const A& aa)" << endl;	//但拷贝构造不会被调用
//	}
//private:
//	int _a;
//};
//int main()
//{
//	int i = 10;
//	double d = i;	//类型转换会产生目标类型的临时变量，再将临时变量的值赋给目标变量
//
//	A aa1(1);	//调用构造
//	A aa2 = 2;	//隐式类型转换 （一个整型转换为自定义类型）
//	//用2调用A类型的构造函数，生成一个A类型的临时变量，再用这个临时变量进行拷贝构造
//	//按语法原义即：构造+拷贝构造
//	//但编译器会优化，优化为2直接构造aa2。编译器不允许在同一个表达式中连续的构造，不允许构造一个变量再去拷贝构造
//	//在连续的表达式里，编译器一般都会优化，以此提高效率
//
//	//A& aa3 = 2;	//无法从int转换为A&,不可通过编译
//	cosnt A& aa3 = 2;	//编译通过，且调用了一次构造函数
//	//用2构造一个临时变量，临时变量具有常性，不可引用，但可以const引用
//
//	
//	return 0;
//}
//#include<string>
//#include<list>
//class string	//string类
//{
//public:
//	string(const char*str)
//	{}
//};
//int main()
//{
//	string name1("zhangsan");	//构造
//	string name2="zhangsan";	//构造+拷贝构造+编译器优化
//	//虽然两者都是构造，且结果相同，但两者过程不同，意义不同
//	return 0;
//}
////而这些特性存在的意义在于：
//class list //链表
//{
//public:
//	void push_back(const string&str)
//	{}
//};
//int main()
//{
//	list lt1;
//	//写法1
//	string name3("lisi");
//	lt1.push_back(name3);
//	//写法2
//	lt1.push_back("lisi");	//lisi可以传入push_back是因为隐式类型转换
//
//	//以上两种写法效果相同，但写法2更加精简
//}
//
// 2.explicit关键字的用法
//如果不想让隐式类型转换发生，可以在构造前加入explicit关键字
//class A
//{
//public:
//	explicit A(int a)
//		:_a(a)
//	{
//		cout << "A(int a)" << endl; //代码运行后，构造函数会被调用
//	}
//	A(const A& aa)
//		:_a(aa._a)
//	{
//		cout << "A(const A& aa)" << endl;	//但拷贝构造不会被调用
//	}
//private:
//	int _a;
//};
//int main()
//{
//	A aa1(1);
//	A aa2 = 2;	//加入explicit关键字编译不再通过，无法从int转换为A类型
//}
//而它的具体使用与智能指针有关

//static静态成员
//
////场景实例：统计A的构造被调用多少次，以便知道创建了多少个对象
//
//int _scount = 0;
//
//class A
//{
//public:
//	A() { ++_scount; }
//	A(const A& t) { ++_scount; }
//	~A() { --_scount; }
//	/*static int GetACount() { return _scount; }*/
//private:
//	/*static int _scount;*/
//};
//
//A aa0;
////A Func(A aa)
////{
////	
////	cout << __LINE__ << ":" << _scount << endl;	  //4
////
////	return aa;
////}
////
////int main()
////{
////	cout << __LINE__ << ":" << _scount << endl;  // 1
////	A aa1;
////
////	static A aa2;
////	Func(aa1);
////	cout << __LINE__ << ":" << _scount << endl;  // 3
////
////	return 0;
////}
//void Func()
//{
//	static A aa2;
//	cout << __LINE__ << ":" << _scount << endl;
//
//	//_scount++;	//但这个代码有一个缺陷。全局变量的劣势：可以在任何地方随意改变
//}
//
//int main()
//{
//	cout << __LINE__ << ":" << _scount << endl;  // 1
//	A aa1;
//
//	Func();  // 3
//	Func();  // 3
//
//	return 0;
//}
//全局变量的劣势：可以在任何地方随意改变
//为了解决这个问题，可以把静态变量作为静态成员变量封装到类中
//class A
//{
//public:
//	A() { ++_scount; }
//	A(const A& t) { ++_scount; }
//	~A() { --_scount; }
//
//	void Func1()
//	{
//		// 非静态可以调用静态
//		GetACount();
//	}
//
//	void Func2()
//	{
//		++_a1;
//	}
//
//	//可以通过公有的静态成员函数访问私有的静态成员变量
//	//静态成员函数的特点：没有this指针，指定类域和访问限定符就可以访问
//	//但静态不可用调用非静态。非静态的成员函数调用需要this指针，静态成员函数没有this
//	static int GetACount() 
//	{ 	
//		//_a1++;	//静态不可用调用非静态。非静态的成员函数调用需要this指针，静态成员函数没有this
//		//Func2()	//静态不可用调用非静态
//		return _scount;
//	}
//private:
//	// 成员变量 -- 属于每一个类对象，存储在对象里面
//	int _a1 = 1;
//	int _a2 = 2;
//
//	// 静态成员变量 -- 属于类，类的每个对象会共享，存储在静态区
//	static int _scount;	//必须在类外（全局位置）定义。静态成员不能给缺省值（缺省值是传给初始化列表的）
//};
//
//
//int A::_scount = 0;	//定义静态成员变量
//int main()
//{
//	cout <<__LINE__<<":"<< A::GetACount() << endl;  
//
//	return 0;
//}
//
////题目：
////求1 + 2 + 3 + ... + n，
////要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句（A?B:C）
//class Sum
//{
//public:
//	Sum()
//	{
//		_ret += _i;
//		++_i;
//	}
//	static int GetRet()
//	{
//		return _ret;
//	}
//private:
//	static int _i;
//	static int _ret;
//};
//int Sum::_i = 1;
//int Sum::_ret = 0;
//class Solution
//{
//public:
//	int Sum_Solution(int n)
//	{
//		Sum a[n];	//n个Sum对象会调用n次构造函数
//
//		return Sum::GetRet();
//	}
//};
////
////题目：
////设计一个类，在类外面只能在栈上或堆上创建对象
//class A
//{
//public:
//	static A GetStackObj()
//	{
//		A aa;
//		return aa;
//	}
//	static A* GetHeapObj()
//	{
//		return new A;
//	}
//private:
//	A() //构造函数私有化 
//	{}
//private:
//	int _a1 = 1;
//	int _a2 = 2;
//};
//int main()
//{
//	//static A aa1;	//静态区
//	//A aa2;			//栈
//	//A* ptr = new A;	//堆
//	A::GetStackObj();
//	A::GetHeapObj();
//
//	return 0;
//}

//5.10

//友元函数
//友元函数可访问类的私有和保护成员，但不是类的成员函数
//友元函数不能用const修饰
//友元函数可以在类定义的任何地方声明，不受类访问限定符限制
//一个函数可以是多个类的友元函数
//友元函数的调用与普通函数的调用原理相同
//class Time
//{
//    friend class Date;   // 声明日期类为时间类的友元类，于是在日期类中就直接访问Time类中的私有成员变量
//
//public:
//    Time(int hour = 0, int minute = 0, int second = 0)
//        : _hour(hour)
//        , _minute(minute)
//        , _second(second)
//    {}
//
//private:
//    int _hour;
//    int _minute;
//    int _second;
//};
//
//class Date
//{
//public:
//    Date(int year = 1900, int month = 1, int day = 1)
//        : _year(year)
//        , _month(month)
//        , _day(day)
//    {}
//
//    void SetTimeOfDate(int hour, int minute, int second)
//    {
//        // 直接访问时间类私有的成员变量
//        _t._hour = hour;
//        _t._minute = minute;
//        _t._second = second;
//    }
//
//private:
//    int _year;
//    int _month;
//    int _day;
//    Time _t;
//};

//内部类
//
//class A
//{
//private:
//    static int k;
//    int h;	//h的大小是必须算的
////public:
//    class B	//内部类其实是外部类的“天生”友元
//    {
//    public:
//        void foo(const A& a)	//因为是友元，所以可以在B类中访问A类对象的成员
//        {
//				cout<<k<<endl;
//				cout<<a.h<<endl;
//        }
//    private:
//        int b;	//B声明在A的类域中，是A的内部类，不占用空间（因为只是声明）
//    };
//};
//
//int A::k = 1;	//k没有存入对象中，故无须计算k的大小
//
//int main()
//{
//    cout << sizeof(A) << endl;	//A类的大小是4
//
//    A aa;		//创建一个A类对象，并不会受到B类的限制
//	 //B bb;	//不可单独创建B类的对象
//    A::B bb;	//必须从A中指定B类来创建对象，会受到A类的限制
//
//	return 0;
//}
//题目：
//求1 + 2 + 3 + ... + n，
//要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句（A ? B : C
//内部类写法：
//class Solution
//{
//	class Sum
//	{
//	public:
//		Sum()
//		{
//			_ret +=_i;
//			++_i;
//		}
//	};
//public:
//	int Sum_Solution(int n)
//	{
//		Sum a[n];
//		return _ret;
//	}
//
//private:
//	static int _i;		//内部类不可访问外部类的成员
//	static int _ret;	//故将外部类成员改为静态成员，使内部类和外部类均可访问
//};
//int Solution::_i = 1;
//int Solution::_ret = 0;

//匿名对象
//
//class A
//{
//public:
//    A(int a = 0)
//        :_a(a)
//    {
//        cout << "A(int a)" << endl;     //检验是否调用构造
//    }
//
//    ~A()
//    {
//        cout << "~A()" << endl;         //检验是否调用析构
//    }
//private:
//    int _a;
//};
//class Solution {
//public:
//    int Sum_Solution(int n) {
//        cout << "Sum_Solution" << endl; //检验是否调用成员函数
//        return n;
//    }
//};
//int main()
//{
//    A aa(1);    //有名对象 - 生命周期在当前函数的局部域
//    A(2);       //匿名对象 - 生命周期仅在当前行。和普通有名对象一样，会传参调用构造
//
//    //调用成员函数
//    //法1：有名对象调用
//    Solution sl;
//    sl.Sum_Solution(10);
//    //法2：匿名对象调用
//    Solution().Sum_Solution(20);    //除了调用成员函数，该行代码还会调用一次析构
//    //因为生命周期仅在当前行，故匿名对象即用即销毁
//
//    //区分 Solution sl; 和 Solution().Sum_Solution(20);
//    //1.Solution().Sum_Solution(20)的Solution后加()，是因为调用普通成员函数要传this指针
//    //2.Solution().Sum_Solution(20)不能写成 Solution::Sum_Solution(20) ,是因为Solution::Sum_Solution(20)是静态成员函数的写法，
//    //  而静态成员函数无须传this指针，故该写法不传this指针，不符合普通成员函数的语法规范
//    //3.Solution sl 后不能加()，是因为加入后编译器无法区分是对象还是函数名
//
//    //A& ra = A(1);     //匿名对象和普通有名对象一样，也具有常性
//    const A& ra = A(1); //const引用会延长匿名对象的生命周期为当前函数局部域
//    
//
//    return 0;
//}
// 
//[补] const引用会延长匿名对象的生命周期为当前函数局部域，实例：
//#include<string>
//void push_back(const string& s)
//{
//    cout << "push_back:" << s << endl;
//}
//int main()
//{
//    string str("11111");
//    push_back(str);  
//    push_back(string("222222"));
//    push_back("222222");
//    
//    return 0;
//}
//

//拷贝对象时的一些编译器优化
// 
//class A
//{
//public:
//    A(int a = 0)
//        :_a(a)
//    {
//        cout << "A(int a)" << endl;
//    }
//
//    A(const A& aa)
//        :_a(aa._a)
//    {
//        cout << "A(const A& aa)" << endl;
//    }
//
//    A& operator=(const A& aa)
//    {
//        cout << "A& operator=(const A& aa)" << endl;
//
//        if (this != &aa)
//        {
//            _a = aa._a;
//        }
//
//        return *this;
//    }
//
//    ~A()
//    {
//        cout << "~A()" << endl;
//    }
//private:
//    int _a;
//};
//void Func1(A aa)
//{
//
//}
////void Func1(const A& aa)   //与上一个函数构成重载，但调用不明确
////{
//// 
////}
//void Func2(const A& aa)
//{
//
//}
//
//A Func3()
//{
//    A aa;
//    return aa;
//}
//
//A& Func4()
//{
//    static A aa;
//    return aa;
//}
//A Func5()
//{
//    A aa;
//    return aa;
//}
//
//int main()
//{
//    A a1;
//    Func1(a1);  //有拷贝构造
//    Func2(a1);  //无拷贝构造
//    Func3();    //拷贝作为函数的返回值 
//    Func4();    //没有拷贝构造
//    //用引用返回，可以减少拷贝，提高效率
//
//    //A& ra = Func5();   //返回值是A拷贝的临时变量，不能这样接收返回值，因为非常量引用（非const引用）只能绑定到左值
//    const A& ra = Func5();
//    A ra = Func5();     //Func5中拷贝一次，=赋值拷贝一次，故一共拷贝两次
//    Func5();            //这种写法拷贝次数同上
//    //编译器优化：同一行的同一个表达式中，连续构造+拷贝构造会合二为一，优化成一次构造
//
//    A aa1;
//    Func1(aa1);     // 不连续的两行表达式，不会优化
//    Func1(A(1));    // 连续的一行表达式，会优化
//    A aa2 = 1;      // 构造+拷贝构造 => 优化为构造
//    Func1(1);       // 构造+拷贝构造 => 优化为构造（与上行其实等价，只不过涉及隐式类型转换）
//
//    A ra1 = Func5();    //同理，会优化
//    A ra2;
//    ra2 = Func5();      //对象已定义，此处是赋值操作，不会优化
//    //第一种种写法会分别调用一次构造、一次拷贝构造、一次析构
//    //但第二种写法会调用两次构造、一次拷贝构造、一次赋值、四次析构，代价较大
//    //注：尽管编译器的优化方案不同，但都会往相似的方向进行优化。故推荐第一种写法，效率更高。
//
//    return 0;
//}

//再次理解类和对象
//类是对现实世界的抽象描述
